\subsubsection{x64: 8 аргументов}

\myindex{x86-64}
\label{example_printf8_x64}
Для того чтобы посмотреть, как остальные аргументы будут передаваться через стек, 
изменим пример ещё раз, 
увеличив количество передаваемых аргументов до 9 
(строка формата \printf и 8 переменных типа \Tint):

\lstinputlisting[style=customc]{patterns/03_printf/2.c}

\myparagraph{MSVC}

Как уже было сказано ранее, первые 4 аргумента в Win64 передаются в регистрах \RCX, \RDX, \Reg{8}, \Reg{9}, а остальные~--- через стек.
Здесь мы это и видим.
Впрочем, инструкция \PUSH не используется, вместо неё при помощи \MOV значения сразу записываются в стек.

\lstinputlisting[caption=MSVC 2012 x64,style=customasmx86]{patterns/03_printf/x86/2_MSVC_x64_RU.asm}

Наблюдательный читатель может спросить, почему для значений типа \Tint отводится 8 байт, ведь нужно только 4?
Да, это нужно запомнить: для значений всех типов более коротких чем 64-бита, отводится 8 байт.
Это сделано для удобства: так всегда легко рассчитать адрес того или иного аргумента.
К тому же, все они расположены по выровненным адресам в памяти.
В 32-битных средах точно также: для всех типов резервируется 4 байта в стеке.

% also for local variables?

\myparagraph{GCC}

В *NIX-системах для x86-64 ситуация похожая, вот только первые 6 аргументов передаются через
\RDI, \RSI, \RDX, \RCX, \Reg{8}, \Reg{9}.
Остальные~--- через стек.
GCC генерирует код, записывающий указатель на строку в \EDI вместо \RDI~--- 
это мы уже рассмотрели чуть раньше: \myref{hw_EDI_instead_of_RDI}.

Почему перед вызовом \printf очищается регистр \EAX мы уже рассмотрели ранее \myref{SysVABI_input_EAX}.

\lstinputlisting[caption=\Optimizing GCC 4.4.6 x64,style=customasmx86]{patterns/03_printf/x86/2_GCC_x64_RU.s}

\myparagraph{GCC + GDB}
\myindex{GDB}

Попробуем этот пример в \ac{GDB}.

\begin{lstlisting}
$ gcc -g 2.c -o 2
\end{lstlisting}

\begin{lstlisting}
$ gdb 2
GNU gdb (GDB) 7.6.1-ubuntu
...
Reading symbols from /home/dennis/polygon/2...done.
\end{lstlisting}

\begin{lstlisting}[caption=ставим точку останова на \printf{,} запускаем]
(gdb) b printf
Breakpoint 1 at 0x400410
(gdb) run
Starting program: /home/dennis/polygon/2 

Breakpoint 1, __printf (format=0x400628 "a=%d; b=%d; c=%d; d=%d; e=%d; f=%d; g=%d; h=%d\n") at printf.c:29
29	printf.c: No such file or directory.
\end{lstlisting}

В регистрах \RSI/\RDX/\RCX/\Reg{8}/\Reg{9} 
всё предсказуемо.
А \RIP содержит адрес самой первой инструкции функции \printf{}.

\begin{lstlisting}
(gdb) info registers
rax            0x0	0
rbx            0x0	0
rcx            0x3	3
rdx            0x2	2
rsi            0x1	1
rdi            0x400628	4195880
rbp            0x7fffffffdf60	0x7fffffffdf60
rsp            0x7fffffffdf38	0x7fffffffdf38
r8             0x4	4
r9             0x5	5
r10            0x7fffffffdce0	140737488346336
r11            0x7ffff7a65f60	140737348263776
r12            0x400440	4195392
r13            0x7fffffffe040	140737488347200
r14            0x0	0
r15            0x0	0
rip            0x7ffff7a65f60	0x7ffff7a65f60 <__printf>
...
\end{lstlisting}

\begin{lstlisting}[caption=смотрим на строку формата]
(gdb) x/s $rdi
0x400628:	"a=%d; b=%d; c=%d; d=%d; e=%d; f=%d; g=%d; h=%d\n"
\end{lstlisting}

Дампим стек на этот раз с командой x/g --- \IT{g} означает \IT{giant words}, т.е. 64-битные слова.

\begin{lstlisting}
(gdb) x/10g $rsp
0x7fffffffdf38:	0x0000000000400576	0x0000000000000006
0x7fffffffdf48:	0x0000000000000007	0x00007fff00000008
0x7fffffffdf58:	0x0000000000000000	0x0000000000000000
0x7fffffffdf68:	0x00007ffff7a33de5	0x0000000000000000
0x7fffffffdf78:	0x00007fffffffe048	0x0000000100000000
\end{lstlisting}

Самый первый элемент стека, как и в прошлый раз, это \ac{RA}.
Через стек также передаются 3 значения: 6, 7, 8.
Видно, что 8 передается с неочищенной старшей 32-битной частью: \GTT{0x00007fff00000008}.
Это нормально, ведь передаются числа типа \Tint, а они 32-битные.
Так что в старшей части регистра или памяти стека остался \q{случайный мусор}.

\ac{GDB} показывает всю функцию \main, если попытаться посмотреть, куда вернется управление после исполнения \printf{}.

\begin{lstlisting}[style=customasmx86]
(gdb) set disassembly-flavor intel
(gdb) disas 0x0000000000400576
Dump of assembler code for function main:
   0x000000000040052d <+0>:	push   rbp
   0x000000000040052e <+1>:	mov    rbp,rsp
   0x0000000000400531 <+4>:	sub    rsp,0x20
   0x0000000000400535 <+8>:	mov    DWORD PTR [rsp+0x10],0x8
   0x000000000040053d <+16>:	mov    DWORD PTR [rsp+0x8],0x7
   0x0000000000400545 <+24>:	mov    DWORD PTR [rsp],0x6
   0x000000000040054c <+31>:	mov    r9d,0x5
   0x0000000000400552 <+37>:	mov    r8d,0x4
   0x0000000000400558 <+43>:	mov    ecx,0x3
   0x000000000040055d <+48>:	mov    edx,0x2
   0x0000000000400562 <+53>:	mov    esi,0x1
   0x0000000000400567 <+58>:	mov    edi,0x400628
   0x000000000040056c <+63>:	mov    eax,0x0
   0x0000000000400571 <+68>:	call   0x400410 <printf@plt>
   0x0000000000400576 <+73>:	mov    eax,0x0
   0x000000000040057b <+78>:	leave  
   0x000000000040057c <+79>:	ret    
End of assembler dump.
\end{lstlisting}

Заканчиваем исполнение \printf, исполняем инструкцию обнуляющую \EAX, удостоверяемся что в регистре \EAX именно ноль.
\RIP указывает сейчас на инструкцию \INS{LEAVE}, т.е. предпоследнюю в функции \main{}.

\begin{lstlisting}
(gdb) finish
Run till exit from #0  __printf (format=0x400628 "a=%d; b=%d; c=%d; d=%d; e=%d; f=%d; g=%d; h=%d\n") at printf.c:29
a=1; b=2; c=3; d=4; e=5; f=6; g=7; h=8
main () at 2.c:6
6		return 0;
Value returned is $1 = 39
(gdb) next
7	};
(gdb) info registers
rax            0x0	0
rbx            0x0	0
rcx            0x26	38
rdx            0x7ffff7dd59f0	140737351866864
rsi            0x7fffffd9	2147483609
rdi            0x0	0
rbp            0x7fffffffdf60	0x7fffffffdf60
rsp            0x7fffffffdf40	0x7fffffffdf40
r8             0x7ffff7dd26a0	140737351853728
r9             0x7ffff7a60134	140737348239668
r10            0x7fffffffd5b0	140737488344496
r11            0x7ffff7a95900	140737348458752
r12            0x400440	4195392
r13            0x7fffffffe040	140737488347200
r14            0x0	0
r15            0x0	0
rip            0x40057b	0x40057b <main+78>
...
\end{lstlisting}
